#include "vmode.h"
#include <cmath>
#include <climits>

//#define _MAX_INT32 (~(1<<31)) 
#define is_integer(dbl) (dbl == int(dbl))

//汉字数字小写
static const char *_num_hanz0[] = { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
//汉字进位小写
static const char *_base_hanz0[] = { /*个*/"", "十", "百", "千", "万", "十", "百", "千", "亿", "十" };
//汉字数字大写
static const char *_num_hanz1 [] =  { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; 
//汉字进位大写
static const char *_base_hanz1[] = { /*个*/"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾" };

//汉字人民币单位
static const char *_rmb_units [] = { "元", "角", "分", "厘", "毫" };

enum  //输入类型
{
    E_VT_INVALID, //
    E_VT_INT, //整数
    E_VT_DBL, //浮点数
    E_VT_DAT, //日期
    E_VT_EXP, //表达式
};

enum
{
    E_VMECODE_0, //normal
    E_VMECODE_1, //unexpected or unknown token
    E_VMECODE_2, //uncomplete express 
    E_VMECODE_3, //unsupport func/op
    E_VMECODE_4  //overflow
};

enum //TOKEN 类型
{
	E_TK_UNDEF = 0, //未定义
    E_TK_FUNC = 1, //函数
    E_TK_OP = 2, //运算符
	E_TK_DBL = 4, //浮点型常量
	E_TK_OPENPA = 8,	//(左圆括号
	E_TK_CLOSEPA = 0x10,	//)右圆括号
    E_TK_COMMA = 0x20, //,
    E_TK_DOT = 0x40, //.
    E_TK_MINUS = 0x80, //负号
    E_TK_INT = 0x100 //整型常量 
};

enum //TOKEN OPERATION
{
    E_TKOP_ADD, //+
    E_TKOP_MINUS, //-
    E_TKOP_MULTI, //*
    E_TKOP_DIV, // /
    E_TKOP_CARET, // ^
    E_TKOP_FACT, // !
    E_TKOP_MOD // %
};
static const char *_vmode_op[] = { "+", "-", "*", "/", "^", "!", "mod"};
//操作符参数个数
static const int _vmode_op_args[] = {2, 2, 2, 2, 2, 1, 2};
//操作符优先级, 值越大, 优先级越高
static const int _vmode_op_level[] = {0, 0, 1, 1, 1, 2, 1};

enum //TOKEN FUNC
{
    E_TKFUNC_SIN,
    E_TKFUNC_COS,
    E_TKFUNC_TAN,
    E_TKFUNC_ARCSIN,
    E_TKFUNC_ARCCOS,
    E_TKFUNC_ARCTAN,
    E_TKFUNC_SQRT,
    E_TKFUNC_AVG,
    E_TKFUNC_VAR,
    E_TKFUNC_STDEV,
    E_TKFUNC_MIN,
    E_TKFUNC_MAX,
    E_TKFUNC_EXP,
    E_TKFUNC_LOG,
    E_TKFUNC_LN
};
static const char *_vmode_func[] =
{ 
    "sin", "cos", "tan", "arcsin", "arccos", "arctan", "sqrt",
    "avg", "var", "stdev", "min", "max", 
    "exp", "log", "ln"
};
//函数参数个数: -1: 至少一个
static const int _vmode_func_args[] = 
{
    1, 1, 1, 1, 1, 1, 1,
    -1, -1, -1, -1, -1,
    1, 1, 1
};

//10进制数字向0~3999的罗马数字的转换：
static  std::string num2roman(int num) 
{
    static const char* c[4][10] =
    {
        {"","I","II","III","IV","V","VI","VII","VIII","IX"},
        {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"},
        {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"},
        {"","M","MM","MMM"}
    };
    std::string roman;
    roman.append(c[3][num / 1000 % 10]);
    roman.append(c[2][num / 100 % 10]);
    roman.append(c[1][num / 10 % 10]);
    roman.append(c[0][num % 10]);
    
    return roman;
}

//0, 1, 10, 11, 100, 101, 111, 1000, 1001, 10000, 10001, 100000, 10001, 1010000
static std::string num2hanz(int num, const char *num_hanz[])
{
    std::string hanz;
    while(num > 0)
    {
        hanz.insert(0,num_hanz[num%10]);
        num /= 10;
    }
    return hanz;
}

static std::string num2hanz_base(int num, const char *num_hanz[], const char *base_hanz[])
{
    std::string hanz;
    for(int last_id=-1, base_id = 0; num > 0; base_id++, num/=10)
    {
        if(0 == num%10 )
        {
            continue;
        }       
        int zbase = base_id & ~0x3;
        if(last_id < 0)
        {
            if(zbase < base_id)
            {
                hanz.insert(0, base_hanz[zbase]);
            } 
        }
        else
        {
            if(last_id < zbase)
            {
                if(last_id + 1 < zbase)
                {
                            
                    hanz.insert(0, num_hanz[0]); //补零    
                }
                if(zbase < base_id)
                {
                
                    hanz.insert(0, base_hanz[zbase]);
                }
            }
            else
            {
                if(last_id + 1 < base_id)
                {
                    hanz.insert(0, num_hanz[0]); //补零   
                }    
            }
        }
        last_id = base_id;
        hanz.insert(0, base_hanz[base_id]);
        hanz.insert(0, num_hanz[num%10]);
    }
    return hanz;
}

static VMode::Candidates convert_num(int num)
{
    VMode::Candidates candidates;
    candidates.push_back(num2hanz_base(num, _num_hanz0, _base_hanz0));
    candidates.push_back(num2hanz_base(num, _num_hanz1, _base_hanz1));
    if(num > 9)
    {
        candidates.push_back(num2hanz(num, _num_hanz0));
        candidates.push_back(num2hanz(num, _num_hanz1));
    }
    if(num < 100)
    {
        candidates.push_back(num2roman(num));
    }
    return candidates;
}

static VMode::Candidates convert_dbl(int n, const char *dbl)
{
    VMode::Candidates cans;
    if(n > 0)
    {
        cans = convert_num(n);
        cans.resize(2);
        cans[0].append("元");
        cans[1].append("元");
    }    
    else // n = 0
    {
        cans.resize(2);
    }
    for(int i=0; dbl[i]; i++)
    {
        if(dbl[i] > '0')
        {
            cans[0].append(_num_hanz0[dbl[i] - '0']);
            cans[1].append(_num_hanz1[dbl[i] - '0']);
            cans[0].append(_rmb_units[i+1]);
            cans[1].append(_rmb_units[i+1]);
        }
    }
    return cans;
    
}

//返回指定日期对应的星期
static std::string calculate_dayOfWeek(int year, int month, int day)
{
    if (month < 3) {
        month += 12;
        year -= 1;
    }
    
    int K = year % 100;
    int J = year / 100;
    
    int h = (day + 13*(month+1)/5 + K + K/4 + J/4 + 5*J) % 7;
    
    // Zeller's Congruence 返回 0=星期六, 1=星期天, ..., 6=星期五
    int dayOfWeek = (h + 5) % 7;
    // 所以我们需要调整返回值以匹配常规的星期表示法
    dayOfWeek = dayOfWeek == 0 ? 6 : dayOfWeek - 1;

    return std::string("星期") + (dayOfWeek == 0 ?"日" : _num_hanz0[dayOfWeek]);
}

static VMode::Candidates convert_date(int n, int y, int r)
{
    VMode::Candidates cans;
    char buf[16];
    cans.resize(2);

    sprintf(buf, "%d", n);
    cans[0].append(buf);
    cans[1].append(convert_num(n)[2]);
    cans[0].append("年");
    cans[1].append("年");

    if(y < 0)
    {
        return cans;
    }
    sprintf(buf, "%d", y);
    cans[0].append(buf);
    cans[1].append(convert_num(y)[0]);
    cans[0].append("月");
    cans[1].append("月");

    if(r < 0)
    {
        return cans;
    }
    sprintf(buf, "%d", r);
    cans[0].append(buf);
    cans[1].append(convert_num(r)[0]);
    cans[0].append("日");
    cans[1].append("日");

    return cans;
}


VMode::VMode() : _cand_type(ET_INVALID)
{
}

VMode::~VMode()
{
}

void VMode::Clear()
{
    _cand_type = ET_INVALID;
    _input.clear();
    _cands.clear();
}

const std::string VMode::Select(int idx)
{ 
    std::string str;
    if(idx < _cands.size())
    {
        str = _cands[idx];
    }
    else
    {
        fprintf(stderr, "ERROR: Index[%d] overflow cands size [%d]\n", idx, (int)_cands.size());
    }
    Clear();
    return str;
}

//E_TK_OPENPA: 默认闭合索引为0
//只有输入为空时会返回E_VMECODE_2
void VMode::lexer()
{
    std::string stoken;
    long long i1, base;
    std::vector<int> pa_stack;
    unsigned int expect = E_TK_FUNC | E_TK_INT | E_TK_OPENPA | E_TK_MINUS;
    int idx = 1; //_input[0]: v

    _ecode = E_VMECODE_0;
    _tk_list.clear();

    if(_input.size() < 2)
    {
        _ecode = E_VMECODE_2;
        return;
    }

LABEL_LEXER:
    while(idx < _input.size() && isspace(_input[idx]))
    {
        idx++;
    }
    if(idx == _input.size())
    {
        if(_tk_list.size() < 1 || _tk_list.back().type == E_TK_DOT || _tk_list.back().type == E_TK_MINUS)
        {
            _ecode = E_VMECODE_2;
        }
        return;
    }
    stoken.clear();
    if((expect & (E_TK_FUNC|E_TK_OP)) && isalpha(_input[idx]))
    {
        do 
        {
            stoken.push_back(tolower(_input[idx++]));
        }while(idx < _input.size() && isalpha(_input[idx]));
        if(expect & E_TK_FUNC)
        {
            int i;
            for(i = 0; i<sizeof(_vmode_func)/sizeof(const char *); i++)
            {
                if(stoken == _vmode_func[i])
                {
                    _tk_list.push_back(VModeToken(E_TK_FUNC, i));
                    expect = E_TK_OPENPA | E_TK_INT | E_TK_MINUS;
                    goto LABEL_LEXER;
                }
            }        
        }
        else if((expect & E_TK_OP) && stoken == "mod")
        {
            _tk_list.push_back(VModeToken(E_TK_OP, E_TKOP_MOD));
            expect = E_TK_OPENPA | E_TK_INT | E_TK_FUNC | E_TK_MINUS;
            goto LABEL_LEXER;
        }
    }
    else if((expect & E_TK_INT) && isdigit(_input[idx]))
    {
        i1 = 0;
        base = 1;
        do 
        {
            if(i1 > LONG_MAX/10) //i1*10 will overflow LONG_MAX
            {
                _ecode = E_VMECODE_4;
                return;
            }
            i1 *= 10;
            base *= 10;
            int next =  _input[idx++] - '0';
            if(i1 > LONG_MAX - next) //i1+next will overflow LONG_MAX
            {
                _ecode = E_VMECODE_4;
                return;
            }
            i1 += next;
        }while(idx < _input.size() && isdigit(_input[idx]));
        if(_tk_list.size() > 0)
        {
            if(E_TK_MINUS == _tk_list.back().type)
            {
                _tk_list.back().type = E_TK_INT;
                _tk_list.back().iv = -i1;
                _isign = -1;
                expect = E_TK_OP | E_TK_DOT;
LABEL_CHECK_PA:
                if(pa_stack.size() > 0)
                {
                    expect |= E_TK_CLOSEPA;
                    auto tidx = pa_stack.back() - 1;
                    if(tidx >= 0 && E_TK_FUNC == _tk_list[tidx].type && _vmode_func_args[_tk_list[tidx].iv] < 0)
                    {
                        expect |= E_TK_COMMA;        
                    }
                }
                goto LABEL_LEXER;
            }
            else if(E_TK_DOT == _tk_list.back().type)
            {
                _tk_list.back().type = E_TK_DBL;
                _tk_list.back().dv = _tk_list.back().iv + i1 * _isign / base;
                expect = E_TK_OP;
                goto LABEL_CHECK_PA;
            }
            
        }
        _isign = 1;
        _tk_list.push_back(VModeToken(E_TK_INT, i1));
        expect = E_TK_OP | E_TK_DOT;
        goto LABEL_CHECK_PA;
        
    }
    else if((expect & E_TK_OPENPA) && '(' ==  _input[idx])
    {
        idx++;
        pa_stack.push_back(_tk_list.size());
        _tk_list.push_back(VModeToken(E_TK_OPENPA));    
        expect = E_TK_OPENPA | E_TK_INT | E_TK_MINUS | E_TK_FUNC;
        goto LABEL_LEXER;
    }
    else if((expect & E_TK_MINUS) && '-' == _input[idx])
    {
        idx++;
        _tk_list.push_back(VModeToken(E_TK_MINUS));
        expect = E_TK_INT;
        goto LABEL_LEXER;
    }
    else if((expect & E_TK_CLOSEPA) && ')' == _input[idx])
    {
        _tk_list[pa_stack.back()].iv = _tk_list.size();
        pa_stack.resize(pa_stack.size()-1);
        _tk_list.push_back(VModeToken(E_TK_CLOSEPA));
        idx++;
        expect = E_TK_OP;
        goto LABEL_CHECK_PA;
    }
    else if((expect & E_TK_COMMA) && ',' == _input[idx])
    {
        _tk_list.push_back(VModeToken(E_TK_COMMA));
        idx++;
        expect = E_TK_FUNC | E_TK_INT | E_TK_MINUS | E_TK_OPENPA;
        goto LABEL_LEXER;

    }
    else if((expect & E_TK_DOT) && '.' == _input[idx])
    {
        _tk_list.back().type = E_TK_DOT;
        expect = E_TK_INT;
        idx++;
        goto LABEL_LEXER;
    }
    else if(expect & E_TK_OP)
    {
        int i;
        for(i = 0; i<E_TKOP_MOD; i++)
        {
            if(*_vmode_op[i] == _input[idx])
            {
                break;
            }
        }
        if(i == E_TKOP_MOD)
        {
            _ecode = E_VMECODE_1;
            return;
        }  
        idx++;
        _tk_list.push_back(VModeToken(E_TK_OP, i));
        if(_vmode_op_args[i] > 1)
        {
            expect = E_TK_FUNC | E_TK_INT | E_TK_MINUS | E_TK_OPENPA;
            goto LABEL_LEXER;
        }
        else
        {
            expect = E_TK_OP;
            goto LABEL_CHECK_PA;
        }

    }
    _ecode = E_VMECODE_1;
}

const VMode::Candidates &VMode::Decode(const std::string &vstr)
{
    int i1, i2, i3;
    char c1, c2, c3, c4;
    std::string res;
    std::string::size_type pos;
    char buf[8];
    for(auto c : vstr)
    {
        if('\b' == c )
        {
            if(_input.size() > 0)
            {
                _input.erase(_input.size()-1, 1);
            }
        }
        else
        {
            _input.push_back(c);
        }
    }
    _cands.clear();
    int match_cnt = sscanf(_input.c_str(), "v%9d%c%4d%c%2d%c%c",
                                             &i1, &c1, &i2, &c2, &i3, &c3, &c4);
    switch(match_cnt)
    {
    case 1:
LABEL_CHECK_DIGIT:
        if(i1 > 0)
        {
            _cand_type = ET_DIGIT;
            _cands = convert_num(i1);
            return _cands;
        }
        break;
    case 2:
        match_cnt = sscanf(_input.c_str(), "v%9d%c%8s", &i1, &c1,buf);
        if(match_cnt == 2)
        {
            if('n' == c1)
            {
                _cand_type = ET_DATE;
                _cands = convert_date(i1, -1, -1);
                return _cands;
            }
            if('.' == c1)
            {
                _cand_type = ET_DIGIT;
                goto LABEL_OUT2;
            }
            if(' ' == c1)
            {
                goto LABEL_CHECK_DIGIT; 
            }
        }
        break;
    case 3:
LABEL_CHECK_DBL:
        if('.' == c1 && i1 >= 0)
        {
            _cand_type = ET_DIGIT;
            _cands = convert_dbl(i1, _input.c_str()+_input.find('.') + 1);
            return _cands;
        }
        break;
    case 4:
        match_cnt = sscanf(_input.c_str(), "v%9d%c%4d%c%8s", &i1, &c1, &i2, &c2, buf);
        if(match_cnt != 4 )
        {
            break;
        }
        if(c1 == 'n' && c2 == 'y' && i1 >= 0 && i1 < 100000 && i2 > 0 && i2 < 13)
        {
            _cand_type = ET_DATE;
            _cands = convert_date(i1, i2, -1);
            return _cands;
        }
        if(c2 == ' ')
        {
            goto LABEL_CHECK_DBL;
        }
    case 5:
        if(i1 < 0 || i1 > 100000 || i2 < 1 || i2 > 12 || i3 < 1 || i3 > 31)
        {
            break;
        }
        if('.' == c1 && '.' == c2)
        {
            _cand_type = ET_DATE;
            _cands =  convert_date(i1, i2, i3);
            std::string wk = calculate_dayOfWeek(i1, i2, i3);
            wk.insert(0, "(");
            wk += ")";
            _cands[0] += wk;
            _cands[1] += wk;
            return _cands;
        }
        break;
    case 6:
LABEL_CHECK_DATE:
        if(i1 < 0 || i1 > 100000 || i2 < 1 || i2 > 12 || i3 < 1 || i3 > 31)
        {
            break;
        }
        if('n' == c1 && 'y' == c2 && 'r' == c3)
        {
            _cand_type = ET_DATE;
            _cands =  convert_date(i1, i2, i3);
            return _cands;
        }
        break;
    case 7:
        match_cnt = sscanf(_input.c_str(), "v%9d%c%4d%c%2d%c%8s",
                                             &i1, &c1, &i2, &c2, &i3, &c3, buf);
        if(match_cnt == 6)
        {
            goto LABEL_CHECK_DATE;
        }
        break;
    default:
        break;
    }
    
    lexer();
    if(E_VMECODE_0 != _ecode)
    {
LABEL_CHK_ERR:
        if(E_VMECODE_2 == _ecode) //uncomplete express
        {
            _cand_type = ET_UNCMPLT;
            goto LABEL_OUT2;
        }
        else
        {
            goto LABEL_OUT;
        }
    }
    res = std::to_string(calculate(0, _tk_list.size()-1));
    //移除小数点后面的无效零后缀
    pos = res.find('.');
    if(pos != res.npos)
    {
        auto pos2 = res.find_last_not_of('0');
        if(pos2 == pos)
        {
            res.erase(pos);
        }
        else 
        {
            res.erase(pos2+1);
        }
    }
    _cands.push_back(res);
    if(E_VMECODE_0 != _ecode)
    {
        _cands.clear(); //清除已经计算的部分结果
        goto LABEL_CHK_ERR;
    }
    _cand_type = ET_EXPV;
    return _cands;

LABEL_OUT:   
    _cand_type = ET_INVALID;
LABEL_OUT2:
    _cands.push_back(_input);
    return _cands;
    
}

//从s开始查找第一个同级别(等括弧)的逗号，找不到返回e+1或者s(e+1<s或者s==,)
int VMode::find_comma(int s, int e)
{
    int pa_cnt = 0;
    while(s <= e)
    {
        if(E_TK_COMMA == _tk_list[s].type)
        {
            if(0 == pa_cnt)
            {
                return s;
            }
        }
        else if(E_TK_OPENPA == _tk_list[s].type)
        {
            pa_cnt++;
        }
        else if(E_TK_CLOSEPA == _tk_list[s].type)
        {
            pa_cnt--;
        }
        s++;
    }
    return s;
}

double VMode::calculate_avg(int s, int e)
{
    int n = 0;
    double sum = 0.0;
    while(s <= e)
    {
        int tidx = find_comma(s, e);
        if(tidx == s)
        {
            _ecode = E_VMECODE_1;
            return 0.0;
        }
        sum += calculate(s, tidx-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }
        n++;
        s = tidx + 1;
    }
    return sum/n;
}


double VMode::calculate_var(int s, int e)
{
    int n = 0;
    double svar = 0.0;
    double avg = calculate_avg(s, e);
    double diff = 0.0;
    if(E_VMECODE_0 != _ecode)
    {
        return 0.0;
    }
    while(s <= e)
    {
        int tidx = find_comma(s, e);
        if(tidx == s)
        {
            _ecode = E_VMECODE_1;
            return 0.0;
        }
        diff = calculate(s, tidx-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }
        diff -= avg;
        svar +=  diff*diff;
        n++;
        s = tidx + 1;
    }
    return svar / n;
}

double VMode::calculate_min(int s, int e)
{
    double min_value = 1.79E+308;
    while(s <= e)
    {
        int tidx = find_comma(s, e);
        if(tidx == s)
        {
            _ecode = E_VMECODE_1;
            return 0.0;
        }
        double t = calculate(s, tidx-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }
        if(t < min_value)
        {
            min_value = t;
        }
        s = tidx+1;
    }
    return min_value;
}

double VMode::calculate_max(int s, int e)
{
    double max_value = -1.79E308;
    while(s <= e)
    {
        int tidx = find_comma(s, e);
        if(tidx == s)
        {
            _ecode = E_VMECODE_1;
            return 0.0;
        }
        double t = calculate(s, tidx-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }
        if(t > max_value)
        {
            max_value = t;
        }
        s = tidx+1;
    }
    return max_value;
}

double VMode::calculate_func(int func, int s, int e)
{
    double arg1 = 0.0;
    if(s > e) // 括号未闭合或为空
    {
        _ecode =  E_VMECODE_2;
        return 0.0;
    }
    switch(func)
    {
    case E_TKFUNC_AVG:
        return calculate_avg(s, e);
    case E_TKFUNC_VAR:
        return calculate_var(s, e);
    case E_TKFUNC_STDEV:
        return pow(calculate_var(s, e), 0.5);
    case E_TKFUNC_MIN:
        return calculate_min(s, e);
    case E_TKFUNC_MAX:    
        return calculate_max(s, e);
    case E_TKFUNC_SIN:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? sin(arg1) : 0.0;
    case E_TKFUNC_COS:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? cos(arg1) : 0.0;
    case E_TKFUNC_TAN:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? tan(arg1) : 0.0;
    case E_TKFUNC_ARCSIN:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? asin(arg1) : 0.0;
    case E_TKFUNC_ARCCOS:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? acos(arg1) : 0.0;
    case E_TKFUNC_ARCTAN:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? atan(arg1) : 0.0;
    case E_TKFUNC_SQRT:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? sqrt(arg1) : 0.0;
    case E_TKFUNC_EXP:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? exp(arg1) : 0.0;
    case E_TKFUNC_LOG:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? log10(arg1) : 0.0;
    case E_TKFUNC_LN:
        arg1 = calculate(s, e);
        return E_VMECODE_0 == _ecode ? log(arg1) : 0.0;
        
    
   
    default:
        _ecode = E_VMECODE_3;
        return 0.0;
    }
}

static long calculate_fact(int n)
{
    long ret = 1;
    while(n > 0)
    {
        ret *= n--;
    }
    return ret;
}


double VMode::calculate_op(int op, double arg1, double arg2)
{
    switch(op)
    {
    case E_TKOP_ADD:
        return arg1 + arg2;
    case E_TKOP_MINUS:
        return arg1 - arg2;
    case E_TKOP_MULTI:
        return arg1 * arg2;
    case E_TKOP_DIV:
        return arg1 / arg2;
    case E_TKOP_CARET:
        return pow(arg1, arg2);
    case E_TKOP_FACT:
        return calculate_fact(int(arg1));       
    case E_TKOP_MOD:
        return long(arg1) % long(arg2);
    default:
        break;
    }

    _ecode = E_VMECODE_3;
    return 0.0;
}

//s: 起始token id
//e: 终止token id
double VMode::calculate(int s, int e)
{
    int tidx = -1; //token index;
    double arg1 = 0.0, arg2 = 0.0;
    
    if(s > e) //括号未闭合或为空, 或者1+-,s:-,e:+
    {
        _ecode = (s < _tk_list.size() && _tk_list[s].type == E_TK_OP) ?E_VMECODE_1: E_VMECODE_2;
        return 0.0;
    }

    switch(_tk_list[s].type)
    {
    case E_TK_INT:
        arg1 = _tk_list[s++].iv;
        break;
    case E_TK_DBL:
        arg1 = _tk_list[s++].dv;
        break;
    case E_TK_OPENPA:
        arg1 = calculate(s+1, _tk_list[s].iv-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }        
        s = _tk_list[s].iv + 1;
        break;
    case E_TK_FUNC:
        s++;
        if(s > e) //sqrt
        {
            _ecode = E_VMECODE_2;
            return 0.0;
        }
        if(E_TK_OPENPA == _tk_list[s].type)
        {
            arg1 = calculate_func(_tk_list[s-1].iv, s+1, _tk_list[s].iv-1);
            if(E_VMECODE_0 != _ecode)
            {
                return 0.0;
            }
            s = _tk_list[s].iv+1;
        }
        else if(E_TK_INT == _tk_list[s].type || E_TK_DBL == _tk_list[s].type)
        {
            arg1 = calculate_func(_tk_list[s-1].iv, s, s);
            if(E_VMECODE_0 != _ecode)
            {
                return 0.0;
            }
            s++;
        }
        else
        {
            _ecode = E_VMECODE_1;
            return 0.0;
        }
        break;

    default:
        _ecode = E_VMECODE_1;
        return 0.0;
    }

LABEL_ARG1:
    if(s > e)
    {
        return arg1;
    }
    if(E_TK_OP == _tk_list[s].type)
    {
        if(1 == _vmode_op_args[_tk_list[s].iv])
        {
            arg1 = calculate_op(_tk_list[s].iv, arg1, arg2);
            s++;
            goto LABEL_ARG1;
        }
        s++;
        if(s > e)
        {
            _ecode = E_VMECODE_2; 
            return 0.0;
        }
        tidx = find_operator(_vmode_op_level[_tk_list[s-1].iv], s, e);
        arg2 = calculate(s, tidx-1);
        if(E_VMECODE_0 != _ecode)
        {
            return 0.0;
        }
        arg1 = calculate_op(_tk_list[s-1].iv, arg1, arg2);
        s = tidx;
        goto LABEL_ARG1;
    }
    else
    {
        _ecode = E_VMECODE_1;
        return 0.0;
    }
}


//从s开始找到第一个优先级小于等于level的运算符token的索引, 没有则返回e+1
int VMode::find_operator(int level, int s, int e)
{
    int pa_cnt = 0; //parentheses count
    while(s <= e)
    {
        if(E_TK_OP == _tk_list[s].type)
        {
            if(0 == pa_cnt && level >= _vmode_op_level[_tk_list[s].iv])
            {
                return s;
            }
        }
        else if(E_TK_OPENPA == _tk_list[s].type)
        {
            pa_cnt++;
        }
        else if(E_TK_CLOSEPA == _tk_list[s].type)
        {
            pa_cnt--;
        }
        s++;
    }
    return s;
}
